<?php
/*
 * @Author: lokei
 * @Date: 2022-11-14 19:08:47
 * @LastEditors: lokei
 * @LastEditTime: 2023-06-06 00:13:12
 * @Description: 
 */

namespace App\Http\Controllers\Pay\Weixin;

use App\Common\Tools\ResultTool;
use App\Common\Tools\Sn;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Controllers\Pay\Weixin\Init;
use App\Models\Pay\Record\PayRecordModel;
use Illuminate\Support\Facades\Redis;
use App\Models\Pay\ConfModel;
use App\Models\Store\StoreModel;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Crypto\AesGcm;

class RefundController extends Controller
{
    public function refund(Request $request)
    {
        $pay_record = PayRecordModel::where('tid', '=', $request->input('pay_tid'))->first();
        $sn = Sn::build_order_no();
        $instance = Init::getInstance($pay_record->store_id);
        $notify_url = env('HOST_URL') . ((env('HOST_PORT') != null && intval(env('HOST_PORT')) > 0) ? (':' . env('HOST_PORT')) : '') . '/api/pay/wx/refund/notify';
        if (config('app.proj_identity') != null && config('app.proj_identity') != '') {
            $notify_url .= '/' . config('app.proj_identity');
        } else {
            $notify_url .= '/0';
        }
        if ($pay_record->store_id > 0) {
            $notify_url .= '/' . $pay_record->store_id;
        } else {
            $notify_url .= '/0';
        }
        $resp = $instance
            ->v3->refund->domestic->refunds
            ->post(['json' => [
                'out_trade_no' => $request->input('pay_tid'),
                'out_refund_no' => $sn,
                'notify_url'   => $notify_url,
                'amount'       => [
                    'total'    => intVal($request->input('total') != null ? floatVal($request->input('total')) * 100 : floatVal($request->input('money')) * 100),
                    'refund'    => intVal(floatVal($request->input('money')) * 100),
                    'currency' => 'CNY'
                ]
            ]]);
        $refund_result = json_decode($resp->getBody()->getContents());
        if ($refund_result->status == 'SUCCESS') {
            $pay_record->refund_sn = $sn;
            $pay_record->refund_id = $refund_result->refund_id;
            $pay_record->status = '5';
            $pay_record->refunded_at = date('Y-m-d H:i:s', time());
            $pay_record->refunded = '1';
            $pay_record->save();

            if (config('app.proj_identity') != null && config('app.proj_identity') != '') {
                $fields = array();
                $fields['pay_tid'] = $request->input('pay_tid');
                $fields['pid'] = config('app.proj_identity');
                Redis::xAdd('refund_success', '*', $fields);
            }
            $res = ResultTool::success();
            $res['data']['status'] = 'SUCCESS';
            return $res;
        } else if ($refund_result->status == 'PROCESSING') {
            $pay_record = PayRecordModel::where('tid', '=', $request->input('pay_tid'))->first();
            $pay_record->refund_sn = $sn;
            $pay_record->refund_id = $refund_result->refund_id;
            $pay_record->status = '5';
            $pay_record->refunded_at = date('Y-m-d H:i:s', time());
            $pay_record->refunded = '0';
            $pay_record->save();
            $res = ResultTool::success();
            $res['data']['status'] = 'PROCESSING';
            return $res;
        } else {
            return ResultTool::fail();
        }
    }

    public function notify($pid, $store_id, Request $request)
    {
        if ($pid != null && $pid != '') {
            $config = config()->all();
            $config['database']['connections']['mysql']['database'] = $pid . '_' . env('DB_DATABASE', 'forge');
            config($config);
        }

        $inWechatpaySignature = $request->header('Wechatpay-Signature'); // 请根据实际情况获取
        $inWechatpayTimestamp = $request->header('Wechatpay-Timestamp'); // 请根据实际情况获取
        $inWechatpaySerial = $request->header('Wechatpay-Serial'); // 请根据实际情况获取
        $inWechatpayNonce = $request->header('Wechatpay-Nonce'); // 请根据实际情况获取
        $inBody = file_get_contents('php://input'); // 请根据实际情况获取，例如: file_get_contents('php://input');

        if ($store_id > 0) {
            $conf = StoreModel::where('id', '=', $store_id)->first();
        } else {
            $conf = ConfModel::first();
        }
        
        $apiv3Key = $conf->signkey; // 在商户平台上设置的APIv3密钥

        // 根据通知的平台证书序列号，查询本地平台证书文件，
        // 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
        if ($pid != null && $pid != '') {
            $platformPublicKeyInstance = Rsa::from('file://' . env('ATTACHMENT_ROOT') . $pid . '/' . 'wxpay/' . 'wechatpay_' . $inWechatpaySerial . '.pem', Rsa::KEY_TYPE_PUBLIC);
        } else {
            $platformPublicKeyInstance = Rsa::from('file://' . env('ATTACHMENT_ROOT') . 'wxpay/' . 'wechatpay_' . $inWechatpaySerial . '.pem', Rsa::KEY_TYPE_PUBLIC);
        }

        // 检查通知时间偏移量，允许5分钟之内的偏移
        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
        $verifiedStatus = Rsa::verify(
            // 构造验签名串
            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
            $inWechatpaySignature,
            $platformPublicKeyInstance
        );
        if ($timeOffsetStatus && $verifiedStatus) {
            // 转换通知的JSON文本消息为PHP Array数组
            $inBodyArray = (array)json_decode($inBody, true);
            // 使用PHP7的数据解构语法，从Array中解构并赋值变量
            ['resource' => [
                'ciphertext'      => $ciphertext,
                'nonce'           => $nonce,
                'associated_data' => $aad
            ]] = $inBodyArray;
            // 加密文本消息解密
            $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
            // 把解密后的文本转换为PHP Array数组
            $inBodyResourceArray = (array)json_decode($inBodyResource, true);

            $pay_record = PayRecordModel::where('refund_id', '=', $inBodyResourceArray['refund_id'])->first();
            if (!is_null($pay_record) && $pay_record->refunded != '1') {
                $pay_record->refunded = '1';
                $pay_record->save();

                if ($pid != null && $pid != '') {
                    $fields = array();
                    $fields['pay_tid'] = $pay_record->tid;
                    $fields['pid'] = $pid;
                    Redis::xAdd('refund_success', '*', $fields);
                }
            }
        }

        echo 'success';
    }
}
